night-shift: gateway token auth + Origin rejection + tests - #1
Merged
Conversation
The gateway had no auth and multipart/form-encoded endpoints (voice, vision) are CSRF-reachable from any webpage without a CORS preflight (S3 in MASTER-FIX-PLAN.md). Every request now must present a shared X-DreamOS-Token header and must not carry an Origin header - real browser requests always set Origin on a cross-origin fetch; the CLI, tests, and other local non-browser callers never do. The token is generated once with secrets.token_hex(32) and persisted to data/gateway_token so it survives a gateway restart. Verified offline (100/100 tests green: 92 existing + 8 new in tests/test_api.py using the FakeRouter/store/vectors fixtures - no network, no API key). Also live-verified end-to-end against a real uvicorn instance: tokenless /stats and /ask and /voice/ask all 401; wrong token 401; valid token + Origin header 403; valid token alone 200 on /stats and reaches real request-handling logic on /ask and /voice/ask (400 on undecodable audio, same as before this change). Note for whoever picks up DreamOS next: DreamOS's gateway fetch calls do not send this token yet, so they will get 401 until DreamOS reads data/gateway_token and sends it as X-DreamOS-Token - flagged in NIGHT_SHIFT.md as a follow-up, intentionally out of scope for this PR (this repo only).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds a
gateway_authmiddleware to the FastAPI app (src/personal_llm/interfaces/api.py):every request must present a shared
X-DreamOS-Tokenheader, and any requestcarrying an
Originheader is rejected outright (403), regardless of tokenvalidity. The token is generated once (
secrets.token_hex(32)) and persistedto
data/gateway_token(newpersonal_llm_gateway_token_pathsetting) so itsurvives a restart.
Why
PROJECT-GENESIS.md section 9, Tier 1 item 6 (MASTER-FIX-PLAN.md Phase 3 item
12, finding S3): the gateway's multipart/form-encoded endpoints (voice,
vision) are CSRF-reachable from any webpage without triggering a CORS
preflight, and there was no auth at all. A real browser always sets
Originon a cross-origin request; the CLI, tests, and any other local non-browser
caller never do - so rejecting
Originoutright closes that hole withoutneeding a CORS allowlist.
How verified
tests/test_api.py(new, 8 cases, offline via the existingFakeRouter/store/vectorsfixtures - no network, no API key): tokenlessrequest rejected, wrong token rejected, correct token allowed on
/statsand round-trips on
/ask,Originheader rejected even with a validtoken,
/voice/askrequires a token, and the token file persists acrosscalls.
uvicorninstance (per this task's "verifytext ask, voice ask, stats end-to-end" requirement): tokenless
/stats,/ask,/voice/askall401; wrong token401; valid token +Originheader
403; valid token alone200on/statsand reaches realrequest-handling logic on
/ask//voice/ask(400on undecodable audio,unchanged from before this PR).
/askwith a valid token hit an unrelatedpre-existing sandbox limitation (no network access to download the
sentence-transformers embedding model from Hugging Face Hub) - not a
regression, and exactly why the test suite mocks embeddings via
FakeRouterinstead of relying on live network calls.Heads-up for the next DreamOS task
DreamOS's gateway fetch calls don't send
X-DreamOS-Tokenyet, so they willget
401from this gateway until DreamOS is updated to readdata/gateway_tokenand send it. Flagged as a follow-up in this repo's../ai-ecosystem/NIGHT_SHIFT.mdentry - intentionally left out of this PR,which only touches personal-llm.